package com.jyd.P1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.jyd.P1.entity.Account;
import com.jyd.P1.enums.ResultEnum;
import com.jyd.P1.exception.ResponseException;
import com.jyd.P1.mapper.AccountMapper;
import com.jyd.P1.pojo.JsonResponse;
import com.jyd.P1.service.AccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author jyd1124
 * @since 2023-07-20
 */
@Slf4j
@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements AccountService {

    @Resource
    AccountMapper accountMapper;

    public String insertAccount(Account account) {
        int i = accountMapper.insert(account);
        if (i <= 0) {
            log.info("AccountServiceImpl.insertAccount: {}", "insert fail");
            return ResultEnum.FAIL.getMsg();
        } else {
            log.info("AccountServiceImpl.insertAccount: {}", "insert success");
            return ResultEnum.SUCCESS.getMsg();
        }
    }

    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public String transfer (String from, String to, Long value) {
        log.info("AccountServiceImpl.transfer request: {} {} {}", from, to, value);
        try {
            if (Objects.isNull(from) || Objects.isNull(to) || Objects.isNull(value)) {
                throw new RuntimeException("transfer parameters error");
            }
            // 验证
            QueryWrapper<Account> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("account_id", from);
            queryWrapper1.last("for update");
            Account fromAccount = accountMapper.selectOne(queryWrapper1);
            QueryWrapper<Account> queryWrapper2 = new QueryWrapper<>();
            queryWrapper2.eq("account_id", to);
            queryWrapper2.last("for update");
            Account toAccount = accountMapper.selectOne(queryWrapper2);
            if (Objects.isNull(fromAccount) || Objects.isNull(toAccount)) {
                throw new ResponseException(ResultEnum.FAIL, "transfer account id error");
            }
            // 转出
            Long fromAmount = fromAccount.getAmount();
            fromAmount -= value;
            if (fromAmount < 0) {
                throw new ResponseException(ResultEnum.FAIL, "insufficient amount");
            }
            Account updateFromAccount = Account.builder()
                    .amount(fromAmount)
                    .build();
            UpdateWrapper<Account> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("account_id", from);
            accountMapper.update(updateFromAccount, updateWrapper);
            // 转入
            Long toAmount = toAccount.getAmount();
            toAmount += value;
            Account updateToAccount = Account.builder()
                    .amount(toAmount)
                    .build();
            updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("account_id", to);
            accountMapper.update(updateToAccount, updateWrapper);
        } catch (ResponseException e) {
            log.info("AccountServiceImpl.transfer error:{} msg:{}", e, e.getErrMsg());
            return ResultEnum.FAIL.getMsg();
        } catch (Exception e) {
            log.info("AccountServiceImpl.transfer error:{}", e.toString());
            return ResultEnum.FAIL.getMsg();
        }
        return ResultEnum.SUCCESS.getMsg();
    }

    public String logOutAmountByAccountId(Integer accountId) {
        UpdateWrapper<Account> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("account_id",accountId).set("is_delete",1);
        int i = accountMapper.update(null,updateWrapper);
        if (i <= 0) {
            log.info("AccountServiceImpl.logOutAmountByAccountId: {}", "logOut fail");
            return ResultEnum.FAIL.getMsg();
        } else {
            log.info("AccountServiceImpl.logOutAmountByAccountId: {}", "logOut success");
            return ResultEnum.SUCCESS.getMsg();
        }
    }
}
